Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start showing inlined functions in stack trace #208

Merged
merged 5 commits into from
Feb 19, 2024
Merged

Conversation

DariaKunoichi
Copy link
Contributor

@DariaKunoichi DariaKunoichi commented Feb 14, 2024

Goal

Customers requested for inline functions to be visible in the stacktrace in bugsnag UI.
Issue: #183

Design

In golang it's recommended to process stacktraces using runtime.CallersFrames.
But unfortunately for inlined functions the frame.Func field is going to be nil.
In this situation we can extract inlined function data from underlying low level data using FuncForPC.

func runtime.FuncForPC(pc uintptr) *runtime.Func
FuncForPC returns a *Func describing the function that contains the given program counter address, or else nil.
If pc represents multiple functions because of inlining, it returns the *Func describing the innermost function, but with an entry of the outermost function.

Changeset

For inline functions extract stack data from PC.
Processing frames from stack now does not exclude newest item on this line.
Tests for notifier do not match one expected line multiple times on this line

For the example in linked issue the Bugsnag UI reported this:
Screenshot 2024-02-14 at 16 15 54

and after this change it now looks like this:
Screenshot 2024-02-14 at 16 15 25

Testing

Changed unit tests that required us to ignore inlined functions - they are now not ignored.

@DariaKunoichi DariaKunoichi self-assigned this Feb 14, 2024
@DariaKunoichi DariaKunoichi changed the base branch from master to next February 15, 2024 11:39
@@ -64,7 +65,7 @@ func New(e interface{}, skip int) *Error {
trace := e.StackTrace()
stack := make([]uintptr, len(trace))
for i, ptr := range trace {
stack[i] = uintptr(ptr) - 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you include some justification on the PR description for this change? It seems fairly fundamental to all our stacktrace reporting, so I'm surprised it's incorrect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is actually moving the whole stack to ignore the newest item. With the -1 added the stack for example looks like:
PTR: main.A
STACK[0]: main.B
PTR: main.B
STACK[1]: main.C
PTR: main.C
STACK[2]: main.main
PTR: main.main
STACK[3]: main.main
PTR: runtime.main
STACK[4]: runtime.main
PTR: runtime.goexit
STACK[5]: runtime.goexit

after changing to not modify the uintptr address:
PTR: main.A
STACK[0]: main.A
PTR: main.B
STACK[1]: main.B
PTR: main.C
STACK[2]: main.C
PTR: main.main
STACK[3]: main.main
PTR: runtime.main
STACK[4]: runtime.main
PTR: runtime.goexit
STACK[5]: runtime.goexit

@@ -187,6 +249,7 @@ func assertStackframesMatch(t *testing.T, expected []errors.StackFrame) {
if strings.HasSuffix(file, expectedFrame.File) && expectedFrame.Name == method {
lastmatch = index
matched++
break
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also provide rationale for this change in the PR description? Why did it pass before and not now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It passed before because the stack was:

  1. func.1
  2. func
    and each function got matched only once so matched count was correct.

When I added expansion of inlines the stack became:

  1. func.1 (for go1.11 and crash for everything else)
  2. func.1
  3. func
    that caused incorrect matching of actual and expected stacks - each actual stackframe could be matched many times - we did not stop comparing after finding first match.
    Matched count exceeded expected stack length and panic happened on the next log. (out of bounds idx)
    Notice that error_test.go has the break in the same place while matching stacks.

Copy link

@lemnik lemnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@DariaKunoichi DariaKunoichi merged commit c6d59e6 into next Feb 19, 2024
53 checks passed
@DariaKunoichi DariaKunoichi deleted the daria-PLAT-7225 branch February 19, 2024 17:49
@DariaKunoichi DariaKunoichi mentioned this pull request Mar 5, 2024
DariaKunoichi added a commit that referenced this pull request Mar 5, 2024
## 2.3.0 (2024-03-05)

### Bug fixes

* Start showing inlined functions in stack trace
  [#208](#208)

* Handle complex structs in metadata
  [#215](#215)
  [Chris Duncan](https://github.com/veqryn)

* Stop trimming everything before "main.go" on main packages
  [#217](#217)
  [Chris Duncan](https://github.com/veqryn)
@dingyaguang117
Copy link

Great Job! Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants